﻿using HalconDotNet;
using Halcon二次开发.Model;
using Halcon二次开发.Model.储放所有单例.储存每个单例界面;
using Halcon二次开发.Model.工具区域的扩展类;
using Halcon二次开发.Model.自定义控件;
using Halcon二次开发.Tools;
using Halcon二次开发.View.模板匹配;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Shapes;
using static System.Windows.Forms.MonthCalendar;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolTip;

namespace Halcon二次开发.Controller.模板匹配
{
    /// <summary>
    /// 模板匹配
    /// </summary>
    public class ShapMatching
    {
        /// <summary>
        /// 矩形2工具包
        /// </summary>
        GenRectangle2 draw;
        /// <summary>
        /// 矩形2工具包
        /// </summary>
        GenCirle drawCirle;
        /// <summary>
        /// 当前图像对象,输入图像
        /// </summary>
        public HObject IntputImage;
        /// <summary>
        /// 模板匹配变量
        /// </summary>
        public HTuple HideOutputShapeModel;
        /// <summary>
        /// 输出变量OutRow,OutColumn,OutAngle是实时位置
        /// OutStandardRow，OutStandardColumn是基准位置，根据模板来决定基准
        /// OutHImage是输出处理好之后的图像
        /// </summary>
        public double OutputRow;
        public double OutputColumn;
        public double OutputPhi;
        public double OutStandardRow;
        public double OutStandardColumn;
        public double OutScoreShape;//当前模板的分数 


        /// <summary>
        /// 控件句柄
        /// </summary>
        HWindow hWindon;
        private H_PMAAlignToolForm pmaForm { get; set; }

        public ShapMatching(H_PMAAlignToolForm pmaForm)
        {
            //获取当前工位
            hWindon = StaicResouce.HwindowFlowNodeUrse.hSmartWindowControl1.HalconWindow;
            this.pmaForm = pmaForm;
            //调用工具包-矩形2
            draw = new GenRectangle2();
            drawCirle = new GenCirle();
        }

        /// <summary>
        /// 画圆
        /// </summary>
        /// <param name="hWindon">句柄</param>
        public void DrawCirle()
        {
            //互锁
            draw.ClearObject(hWindon);
            CirleControl cirle = (CirleControl)pmaForm.groupBox3.Controls[0];
            double x = double.Parse(cirle.XUpDown.Value + "");
            double y = double.Parse(cirle.YUpDown.Value + "");
            double radius = double.Parse(cirle.RaduisUpDown.Value + "");
            drawCirle.DrawCirle(hWindon, x, y, radius, pmaForm.textBox3.Text, cirle.XUpDown, cirle.YUpDown, cirle.RaduisUpDown);
        }
        /// <summary>
        /// 画矩形
        /// </summary>
        /// <param name="hWindon">句柄</param>
        public void DrawRectangle2()
        {
            //互锁
            drawCirle.ClearObject(hWindon);
            Rectangle2Control rectangle2 = (Rectangle2Control)pmaForm.groupBox3.Controls[0];
            double x = double.Parse(rectangle2.XUpDown.Value + "");
            double y = double.Parse(rectangle2.YUpDown.Value + "");
            double phi = double.Parse(rectangle2.PhiUpDown.Value + "");
            double length1 = double.Parse(rectangle2.Length1UpDown.Value + "");
            double length2 = double.Parse(rectangle2.Length2UpDown.Value + "");
            draw.DrawRectangle2(hWindon, x, y, phi, length1, length2, pmaForm.textBox3.Text, rectangle2.XUpDown, rectangle2.YUpDown, rectangle2.PhiUpDown, rectangle2.Length1UpDown, rectangle2.Length2UpDown);
        }
        /// <summary>
        /// 保存模板
        /// </summary>
        public void SaveShapeModel(string path)
        {
            if (IntputImage == null || ImageIsNg())
            {
                throw new Exception("当前图像为空");
            }
            if (HideOutputShapeModel == null)
            {
                return;
            }
            HOperatorSet.WriteShapeModel(HideOutputShapeModel, path);
        }
        /// <summary>
        /// 创建模板
        /// </summary>
        /// <param name="hWindon">句柄</param>
        //paper是用来决定是创建模板时建立模板的
        private static bool paper = false;
        public void CreatShapeModel()
        {
            HObject ROI_0 = null;
            if (IntputImage == null || ImageIsNg())
            {
                throw new Exception("当前图像为空");
            }
            HDrawingObjectEx region = null;
            //获取位置信息,谁有值就执行谁
            {
                draw.GetPoint(out HDrawingObjectEx region1);
                drawCirle.GetPoint(out HDrawingObjectEx region2);
                if (region1 != null)
                {
                    //矩形
                    region = region1;
                    HOperatorSet.GenRectangle2(out ROI_0, region.hTuples[0], region.hTuples[1], region.hTuples[2], region.hTuples[3], region.hTuples[4]);
                    draw.ClearObject(hWindon);
                }
                else if (region2 != null)
                {
                    //圆形
                    region = region2;
                    HOperatorSet.GenCircle(out ROI_0, region.hTuples[0], region.hTuples[1], region.hTuples[2]);
                    drawCirle.ClearObject(hWindon);
                }
            }
            paper = true;
            if (ROI_0 == null) return;

            //
            HOperatorSet.SetSystem("clip_region", "false");

            HOperatorSet.ReduceDomain(IntputImage, ROI_0, out HObject imageReduced);

            try
            {
                // 模板接受的角度
                HOperatorSet.CreateScaledShapeModel(imageReduced, int.Parse(pmaForm.numericUpDown5.Value.ToString()), (new HTuple(-360).TupleRad())
                , (new HTuple(360).TupleRad()), "auto", 0.5, 1.2, "auto", "auto", "ignore_local_polarity",
                "auto", int.Parse(pmaForm.numericUpDown2.Value.ToString()), out HideOutputShapeModel);
            }
            catch (HOperatorException e)
            {
                if (e.GetErrorCode() == 3111)
                {
                    DrawRectangle2();
                    CreatShapeModel();
                }
            }


            HOperatorSet.GetShapeModelContours(out HObject ho_ModelContours, HideOutputShapeModel, 1);
            HOperatorSet.AreaCenter(ROI_0, out HTuple hv_Area, out HTuple hv_Row1, out HTuple hv_Column1);

            //几何变换的实现
            HOperatorSet.HomMat2dIdentity(out HTuple hv_HomMat2DIdentity);
            HOperatorSet.HomMat2dTranslate(hv_HomMat2DIdentity, hv_Row1, hv_Column1, out HTuple hv_HomMat2DTranslate);
            HOperatorSet.HomMat2dRotate(hv_HomMat2DTranslate, 0, hv_Row1, hv_Column1, out HTuple hv_HomMat2DRotate);
            HOperatorSet.HomMat2dScale(hv_HomMat2DRotate, 1, 1, hv_Row1, hv_Column1, out HTuple hv_HomMat2DScale);
            HOperatorSet.AffineTransContourXld(ho_ModelContours, out HObject ho_ContoursAffineTrans, hv_HomMat2DScale);

            HOperatorSet.DispObj(ho_ContoursAffineTrans, hWindon);
            //创建一个供存储基准数据的文件夹
            Directory.CreateDirectory(pmaForm.standardPath);
        }
        /// <summary>
        /// 寻找模版CreatShape
        /// </summary>
        /// <param name="path">模板路径</param>
        /// <param name="hWindon">句柄</param>
        /// /// <param name="value1">模板匹配的分数下限</param>
        /// /// <param name="value2">模板匹配的分数上限</param>
        public void Run()
        {
            if (IntputImage == null || ImageIsNg())
            {
                throw new Exception("当前图像为空");
            }
            //清除模型
            ClearTwoObject(hWindon);
            pmaForm.dataGridView1.Rows.Clear();
            pmaForm.textBox4.Text = "";
            try
            {
                HOperatorSet.ReadShapeModel(pmaForm.filePath, out HTuple hv_ModelID2);
                HOperatorSet.GetShapeModelContours(out HObject ho_ModeContours, hv_ModelID2, 1);
                if (hv_ModelID2 == null)
                {
                    throw new Exception("寻找模板失败");
                }
                //金字塔层数越高处理速度越快 NumLevels
                //搜索启发式的（0：安全 但速度很慢;1：快速但可能会错过匹配项） Greediness
                HOperatorSet.FindScaledShapeModel(IntputImage, hv_ModelID2, (new HTuple(int.Parse(pmaForm.numericUpDown4.Value.ToString()))).TupleRad(), (new HTuple(int.Parse(pmaForm.numericUpDown3.Value.ToString()))).TupleRad(),

                    0.5, 1.5, 0.1, 1, 0.8, pmaForm.comboBox1.SelectedItem.ToString(), int.Parse(pmaForm.numericUpDown5.Value.ToString()), double.Parse(pmaForm.numericUpDown6.Value.ToString()),

                    out HTuple hv_RowShape, out HTuple hv_ColumnShape, out HTuple hv_AngleShape, out HTuple hv_ScaleShape, out HTuple hv_ScoreShape);
                //HOperatorSet.FindScaledShapeModels(IntputImage, hv_ModelID2, (new HTuple(int.Parse(pmaForm.numericUpDown4.Value.ToString()))).TupleRad(), (new HTuple(int.Parse(pmaForm.numericUpDown3.Value.ToString()))).TupleRad(),

                //    0.5, 1.5, 0.1, 1, 0.8, "least_squares", int.Parse(pmaForm.numericUpDown5.Value.ToString()), double.Parse(pmaForm.numericUpDown6.Value.ToString()),

                //    out HTuple hv_RowShape, out HTuple hv_ColumnShape, out HTuple hv_AngleShape, out HTuple hv_ScaleShape, out HTuple hv_ScoreShape,out HTuple hv_Model);
                //记录一下方便后续调用
                if (paper)
                {
                    //点击记录基准数据
                    OutStandardRow = hv_RowShape;
                    OutStandardColumn = hv_ColumnShape;
                    //将这个基准数据进行保存下来
                    List<double> doubleList=new List<double>();
                    doubleList.Add(OutStandardRow);
                    doubleList.Add(OutStandardColumn);
                    //将这个数据进行持久化
                    HelpJsons.Write<double>(doubleList, pmaForm.standardPath+"\\"+ "standar.txt");
                    paper = false;
                }
                //添加给输出  x，y位置，角度
                try
                {
                    OutputRow = hv_RowShape;
                    OutputColumn = hv_ColumnShape;
                    OutputPhi = hv_AngleShape;
                }
                catch
                {
                    throw new Exception("寻找模板失败");
                }


                
                //判断是否在分数内
                if (hv_ScoreShape > (double)pmaForm.numericUpDown1.Value)
                {
                    HOperatorSet.HomMat2dIdentity(out HTuple hv_HomMat2DIdentity);
                    HOperatorSet.HomMat2dTranslate(hv_HomMat2DIdentity, hv_RowShape, hv_ColumnShape, out HTuple hv_HomMat2DTranslate);
                    HOperatorSet.HomMat2dRotate(hv_HomMat2DTranslate, hv_AngleShape, hv_RowShape, hv_ColumnShape,
                        out HTuple hv_HomMat2DRotate);
                    HOperatorSet.HomMat2dScale(hv_HomMat2DRotate, hv_ScaleShape, hv_ScaleShape, hv_RowShape, hv_ColumnShape,
                        out HTuple hv_HomMat2DScale);

                    HOperatorSet.SetColor(hWindon, "green");
                    HOperatorSet.AffineTransContourXld(ho_ModeContours, out HObject ho_AffineTransContour, hv_HomMat2DScale);
                    HOperatorSet.DispObj(ho_AffineTransContour, hWindon);

                    pmaForm.dataGridView1.Rows.Add(0, hv_RowShape, hv_ColumnShape, hv_AngleShape, hv_ScaleShape, hv_ScoreShape);
                }
                else
                {
                    pmaForm.textBox4.Text = "丢失分数为: " + hv_ScoreShape;
                    throw new Exception("匹配失败");
                }


                //将我们的模板匹配的分数给到输出接口
                OutScoreShape = hv_ScoreShape;
            }
            catch(Exception ex)
            {
                string str = string.Empty;
                if (ex.Message.Contains("匹配失败!"))
                {
                    str = "匹配失败!";
                }
                else if (ex.Message.Contains("寻找模板失败!"))
                {
                    str = "寻找模板失败!";
                }
                else
                {
                    str = "模板匹配运行失败，请检查你的模板是否正确!";
                }
                throw new Exception(str);
            }
        }
        /// <summary>
        /// 计量模型移动方法
        /// </summary>
        public void Move(Object sender)
        {
            NumericUpDown number = (sender as NumericUpDown);
            UserControl control = (UserControl)number.Parent;
            if (control.Name == "Rectangle2Control")
            {
                Rectangle2Control rectangle = (Rectangle2Control)number.Parent;
                if (rectangle != null)
                {
                    draw.Move(hWindon, double.Parse(rectangle.XUpDown.Value + ""), double.Parse(rectangle.YUpDown.Value + ""), double.Parse(rectangle.PhiUpDown.Value + ""), double.Parse(rectangle.Length1UpDown.Value + "")
                        , double.Parse(rectangle.Length2UpDown.Value + ""), pmaForm.textBox3.Text);
                }
            }
            else if (control.Name == "CirleControl")
            {
                CirleControl cirle = (CirleControl)number.Parent;
                if (control != null)
                {
                    drawCirle.Move(hWindon, double.Parse(cirle.XUpDown.Value + ""), double.Parse(cirle.YUpDown.Value + ""), double.Parse(cirle.RaduisUpDown.Value + ""), pmaForm.textBox3.Text);
                }
            }
        }
        public void ClearTwoObject(HWindow hWindon)
        {
            //清除模型
            if (draw != null)
            {
                draw.ClearObject(hWindon);
            }

            if (drawCirle != null)
            {
                drawCirle.ClearObject(hWindon);
            }
        }


        /// <summary>
        /// 工具的单次运行
        /// </summary>
        public void Tool_Run()
        {
            if (IntputImage == null || ImageIsNg())
            {
                throw new Exception("当前图像为空");
            }
            hWindon.ClearWindow();
            HOperatorSet.DispObj(IntputImage, hWindon);
            Run();
        }
        public bool ImageIsNg()
        {
            foreach (TreeNode node in StaicResouce.HwindowFlowNodeUrse.treeView1.Nodes)
            {
                if (node.Nodes.Count == 0) continue;
                if (node.Nodes[0].Tag == this && node.Nodes[0].Text.Contains("<—"))
                {
                    return false;
                }
            }
            return true;
        }
    }
}
